本文开发环境配置
需要的工具优麒麟等deb系fedora等rpm系autotools工具apt install autoconf automake libtoolyum install autoconf automake libtoolglib库apt install libglib2.0-devyum install glib2-develnotify库apt install libnotify-devyum install libnotify-devel
项目资源: csdn链接:linux autotools多目录编程实例 github链接: 暂无
1、目标:解决子目录之间源码包含与编译依赖的关系
本篇重在理解多目录项目工程中,Makefile.am文件怎么编写,以及如何解决不同目录之间的源码依赖关系 即重点应该查看源码#include与Makefile.am中_LIBADD _LDADD字段
2、项目的README文件:
1、命令行手动编译 gcc time-notify/time-notify.c time-notify/time-notify.h src/show-notify.c src/show-notify.h test/main.c `pkg-config --cflags --libs glib-2.0 gdk-pixbuf-2.0` -I./src -I./time-notify -I. -lnotify
2、重点关注:
- configure.ac内subdir-objects关键字的作用:多目录工程中,automake要使用该参数
- Makefile.am中.la文件的使用:用于解决gcc链接阶段的依赖问题
3、新增知识难度:
- 源码目录结构的改变:所有源码在同一目录 ---> 项目中存在多个目录,每个目录下均有源代码
- 链接形式的改变:单一目录时链接寻找 .o 文件 ---> 多目录时链接寻找 .la 文件
4、一些改变:(针对于案例入门项目的改变)
根据步骤3中新增的难度,主要涉及2方面的改变:
- configure.ac
1) 需要增加 subdir-objects 关键字:---> AM_INIT_AUTOMAKE(subdir-objects)
2) 需要增加编译器检测:---> AC_PROG_LIBTOOL
3) 列出某一个需要生成 Makfile 文件的目录: ---> AC_CONFIG_FILES([....]),具体参见configure.ac文件
- Makefile.am
Makefile 的本质应该在于自动寻找依赖,那么这一块的改变主要是在Makefile.am中指定多目录时如何寻找依赖。
参见 time-notify/Makefile.am 中 libtime_notify_la_LIBADD 条目
5、autotools系列命令运行顺序:(主要是新增libtoolize命令)
- autoscan、mv configure.sacn configure.ac
- autoheader
- 编写Makefile.am文件
- aclocal
- libtoolize
- automake --copy --add-missing
- autoconf
- ./configure
6、一个Makefile.am书写说明
问题描述:我编写这个项目案例时在 time-notify/Makefile.am 的 libtime_notify_la_SOURCES 条目中使用 $(top_srcdir) 变量时,项目编译不过去。(具体写法可见该文件的最后一行)
资料查找:出现问题后我发现开源Makefile.am在 _SOURCES 条目中列举源文件时,如果是与Makefile.am同目录的源文件,则不使用 $(top_srcdir) 变量。
问题解决:删去该变量后,项目可以编译通过;不确定与环境是否有关,读者可以自行尝试。
3、项目的configure.ac文件
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
#autoscan命令的版本
AC_PREREQ([2.69])
#项目名称,版本号,作者联系方式
AC_INIT([notify-plus], [1.0], [[email protected]])
#项目需要使用automake工具,所以增加下面这一行
#subdir-objects:多目录编程时,必须要有该关键字
AM_INIT_AUTOMAKE(subdir-objects)
#指定$(top_srcdir)的值为config.h.in所在的目录
AC_CONFIG_SRCDIR([config.h.in])
#AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.编译器检测
#自动检测要使用的C编译器
AC_PROG_CC
AC_PROG_CPP
#使用pkg-config根据.pc文件自动为我们生成 _CFLAGS 和 _LIBS
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
#生成.la文件需要
AC_PROG_LIBTOOL
#下面这个写法是参考开源项目的写法
LIBNOTIFY_REQUIRED_VERSION=0.7.0
GLIB_REQUIRED_VERSION=2.17.3
dnl ------------------------------
dnl check for libnotify
dnl ------------------------------
#利用pkg-config生成 _CFLAGS _LIBS
PKG_CHECK_MODULES(LIBNOTIFY,libnotify >= $LIBNOTIFY_REQUIRED_VERSION)
#AC_SUBST输出能够被Makefile.am使用的变量,这里体现出automake从autoconf继承的关系
AC_SUBST(LIBNOTIFY_CFLAGS)
AC_SUBST(LIBNOTIFY_LIBS)
dnl ------------------------------
dnl check for glib-2.0
dnl ------------------------------
PKG_CHECK_MODULES(GLIB2,glib-2.0 >= $GLIB_REQUIRED_VERSION)
AC_SUBST(GLIB2_CFLAGS)
AC_SUBST(GLIB2_LIBS)
# Checks for libraries.检测系统库是否存在
AC_CHECK_LIB([glib-2.0],[notify])
# Checks for header files.检测头文件是否存在
AC_CHECK_HEADERS([glib.h],[libnotify/notify.h])
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.指定要生成Makefile文件的地方
# 多目录项目编程时自然要列出多个目录
AC_CONFIG_FILES([Makefile
src/Makefile
time-notify/Makefile
test/Makefile])
AC_OUTPUT
4、项目所有的Makefile.am文件
1) 项目根目录的总Makefile.am
#定义NULL时,= 后面直接换行,不要增加空格
NULL =
#下面这行是我在调试项目时,系统提示考虑增加的,具体用处读者自查
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
# 在这里列举子目录时,如果目录之间存在依赖关系时,那么一定要在这里使用先后关系体现出来(被依赖的写在前面)
# 读者可以尝试打乱这里写好的顺序,自己跑一遍编译流程,查看编译报错
SUBDIRS = \
src \
time-notify \
test \
$(NULL)
2)src目录的Makefile.am
NULL =
#表示最终要生成一个libtool文件,用于其他目录下源码的编译链接
noinst_LTLIBRARIES = libshow-notify.la
# $(includdir)的值由autoconf为我们自动生成,
# 默认是'/urs/include' 或 '/usr/local/include'
# _CPPFLAGS指定预处理阶段头文件的查找目录(gcc -I)
libshow_notify_la_CPPFLAGS = \
-I$(includedir) \
$(GLIB2_CFLAGS) \
$(LIBNOTIFY_CFLAGS) \
$(NULL)
# automake可以从autoconf继承变量
# 即Makefile文件用到下列变量时可以在configure脚本文件中寻找这些变量的定义
# 当然,这些变量最初是由开发者在configure.ac文件中增加的
# _LIBADD指定链接阶段so库的查找路径(gcc -l)
libshow_notify_la_LIBADD = \
$(GLIB2_LIBS) \
$(LIBNOTIFY_LIBS) \
$(NULL)
#_SOURCES指定要生成文件所依赖的源代码文件
libshow_notify_la_SOURCES = \
$(top_srcdir)/src/show-notify.h \
show-notify.c \
$(NULL)
3)time-notify目录的Makefile.am
NULL =
#要生成一个libtool文件
noinst_LTLIBRARIES = libtime-notify.la
libtime_notify_la_CFLAGS = \
-I$(top_srcdir)/src/ \
$(GLIB2_CFLAGS) \
$(NULL)
# 后续会总结出 _LIBADD 与 LDADD 的区别
libtime_notify_la_LIBADD = \
$(top_srcdir)/src/libshow-notify.la \
$(GLIB2_LIBS) \
$(NULL)
libtime_notify_la_SOURCES = \
time-notify.c \
time-notify.h \
$(NULL)
# 这个对应于README文件里描述的 $(top_srcdir) 变量的问题
#$(top_srcdir)/time-notify/time-notify.c
4)test目录的Makefile.am
NULL =
#表示要生成一个名为 test-show-notify 的二进制文件
bin_PROGRAMS = \
test-show-notify \
$(NULL)
#表示main.c内包含的头文件time-notify.h要从time-notify目录下查找
test_show_notify_CPPFLAGS = \
-I$(top_srcdir)/time-notify \
$(NULL)
# _LDADD指定生成二进制文件所有要链接的so库(gcc -l)
test_show_notify_LDADD = \
$(top_srcdir)/time-notify/libtime-notify.la \
$(NULL)
# _SOURCES指定要生成的二进制文件所依赖的源码文件
test_show_notify_SOURCES = \
main.c \
$(NULL)
|